#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "CodeEditor.h"
#include "OStreamToTextEdit.h"
#include "LLparse.h"
#include "Semantic.h"
#include <fstream>
#include <iostream>
#include <functional>

#include <QFileDialog>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QFileInfo>
#include <QDebug>

extern Token tokenList[1024];
extern TreeNode* treeroot;
extern TreeNode* LLtreeroot;
extern SymbolTable* smbltable;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->editorTabWidget->addTab(new CodeEditor(),"new file");

    OStreamToTextEdit* redirect = new OStreamToTextEdit(std::cerr,ui->ErrorMessage);
    status = UNCOMPILED;//未编译状态
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_actionNew_File_triggered()
{
    ui->editorTabWidget->addTab(new CodeEditor(),"new file");
}

void MainWindow::on_actionOpen_File_triggered()
{
    QString fullPath = QFileDialog::getOpenFileName(this, "Open the file");


    QFileInfo fileInfo(fullPath);
    QString filename(fileInfo.fileName());

    CodeEditor* codeEditor = new CodeEditor(fullPath);
    ui->editorTabWidget->addTab(codeEditor,filename);
	ui->editorTabWidget->setCurrentWidget(codeEditor);
}

void MainWindow::on_editorTabWidget_tabCloseRequested(int index)
{
    this->on_actionSave_triggered();
    ui->editorTabWidget->removeTab(index);
}

void MainWindow::on_actionSave_triggered()
{
    CodeEditor * curEditor = dynamic_cast<CodeEditor *>(ui->editorTabWidget->currentWidget());
    curEditor->saveToFile();
    setCurrentEditorTabTitle(curEditor->getFilePath());
    ui->Console->append("Flie " + curEditor->getFilePath() + " had been saved !!");
}

void MainWindow::on_actionLexical_Analysis_triggered()
{
    if(status == UNCOMPILED)
    {
        CodeEditor * curEditor = dynamic_cast<CodeEditor *>(ui->editorTabWidget->currentWidget());
        curEditor->saveToFile();
        QString filePath = curEditor->getFilePath();
        setCurrentEditorTabTitle(filePath);
        FILE* fp;
        fp = fopen(filePath.toStdString().c_str(), "r");

        for (int i = 0; i < 1024; i++)
        {
            tokenList[i].index = i;
        }

        if(lexicalAnalyse(fp))
        {
            ui->CompileOutput->append("Lexical Analysis result:");
            std::list<string> tokenSequence = printTokenList(tokenList);
            for(auto& token:tokenSequence){
                ui->CompileOutput->append(token.c_str());
                status = LEXICAL;
            }
        }
        else
        {
            ui->ErrorMessage->append("Lexical Error Message:");
            appendFileToTextEdit("Lexerror.txt", *ui->ErrorMessage);
            status = ERROR;
        }
        fclose(fp);
    }
    else
    {
        ui->Console->append("Lexical Analysis had been completed!");
        ui->Console->append("If you wanna try again, please clear message frist ^-^ ");
    }
}

void MainWindow::on_actionSyntax_Analysis_triggered()
{

}

void MainWindow::setCurrentEditorTabTitle(QString filePath)
{
    if(!filePath.isEmpty()){
        QFileInfo fileInfo(filePath);
        QString fileName(fileInfo.fileName());
        ui->editorTabWidget->setTabText(ui->editorTabWidget->currentIndex(),fileName);
    }
}

void MainWindow::appendFileToTextEdit(const QString filpath,QTextEdit& textEdit)
{
    QFile file(filpath);
    if(!file.exists()){
       qDebug() << "NO existe el archivo "<<filpath;
    }
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)){
       QTextStream stream(&file);
       while (!stream.atEnd()){
           textEdit.append(stream.readLine());
       }
    }
    file.close();
}

void MainWindow::on_actionClear_message_triggered()
{
    ui->ErrorMessage->clear();
    ui->CompileOutput->clear();
    status = UNCOMPILED;
    ui->Console->append("Message Clear had been done !!");
}

//递归——NEW
void MainWindow::on_actionRecursive_triggered()
{
    CodeEditor * curEditor = dynamic_cast<CodeEditor *>(ui->editorTabWidget->currentWidget());
    curEditor->saveToFile();
    QString filePath = curEditor->getFilePath();
    setCurrentEditorTabTitle(filePath);
    QString syntaxFile = filePath + ".RDparse";

    switch (status) {
    case UNCOMPILED:
        //进行词法分析，再进行语法分析
//        on_actionLexical_Analysis_triggered();
        FILE* fp;
        fp = fopen(filePath.toStdString().c_str(), "r");

        for (int i = 0; i < 1024; i++)
        {
            tokenList[i].index = i;
        }

        if(lexicalAnalyse(fp))
        {
            status = LEXICAL;
            on_actionRecursive_triggered();
        }
//        on_actionRecursive_triggered();
        else
        {
            ui->ErrorMessage->append("Lexical Error Message:");
            appendFileToTextEdit("Lexerror.txt", *ui->ErrorMessage);
        }
        break;
    case LEXICAL:
        InitPredict();
        treeroot = parserecur();
        if(treeroot==NULL)
        {
            ui->ErrorMessage->append("Recursive Syntax Analysis runs wrong!!\n");
            appendFileToTextEdit("out.txt", *ui->ErrorMessage);
        }
        else
        {
            outputParserTree(treeroot,"parserRecurTree.txt");
            ui->CompileOutput->append("Recursive Syntax Analysis result:\n==============\n");
            appendFileToTextEdit("parserRecurTree.txt",*ui->CompileOutput);
            status = SYNTAXRD;
        }
        break;
    case SYNTAXRD:
        ui->Console->append("Recursive Syntax Analysis had been done!!\n");
        ui->Console->append("If you wanna try again, please clear message frist ^-^ ");
        break;
    case SYNTAXLL1:
        InitPredict();
        treeroot = parserecur();
        if(treeroot==NULL)
        {
            ui->ErrorMessage->append("Recursive Syntax Analysis runs wrong!!\n");
            appendFileToTextEdit("out.txt", *ui->ErrorMessage);
        }
        else
        {
            outputParserTree(treeroot,"parserRecurTree.txt");
            ui->CompileOutput->append("Recursive Syntax Analysis result:\n=============\n");
            appendFileToTextEdit("parserRecurTree.txt",*ui->CompileOutput);
            status = SYNTAX;
        }
        break;
    case SEMANTIC:
        ui->Console->append("Syntax Analysis had been done!!\n");
        break;
    case SYNTAX:
        ui->Console->append("Syntax Analysis has both been done!!\n");
        break;
    case ERROR:
        ui->Console->append("Errors happen in this SNL program!!\nRecursive analysis can not be done..\n");
        break;
    default:
        break;
    }
}

//LL1分析方法
void MainWindow::on_actionLL_1_triggered()
{
    CodeEditor * curEditor = dynamic_cast<CodeEditor *>(ui->editorTabWidget->currentWidget());
    curEditor->saveToFile();
    QString filePath = curEditor->getFilePath();
    setCurrentEditorTabTitle(filePath);
    QString syntaxFile = filePath + ".LL1parse";

    switch (status) {
    case UNCOMPILED:
        FILE* fp;
        fp = fopen(filePath.toStdString().c_str(), "r");
        for (int i = 0; i < 1024; i++)
        {
            tokenList[i].index = i;
        }

        if(lexicalAnalyse(fp))
        {
            status = LEXICAL;
            on_actionLL_1_triggered();
        }
        else
        {
            ui->ErrorMessage->append("Lexical Error Message:");
            appendFileToTextEdit("Lexerror.txt", *ui->ErrorMessage);
        }
        break;
    case LEXICAL:  
        if(parserLL1())
        {
            outputParserTree(LLtreeroot,"parserLL1Tree.txt");
            ui->CompileOutput->append("Syntax Analysis LL result:\n===========\n");
            appendFileToTextEdit("parserLL1Tree.txt",*ui->CompileOutput);
            status = SYNTAXLL1;
        }
        else
        {
            outputParserLL1Errors(false,"parserLL1Errors.txt");
            ui->ErrorMessage->append("LL1 Syntax Analysis runs wrong!!\n");
            appendFileToTextEdit("parserLL1Errors.txt", *ui->ErrorMessage);
            status = ERROR;
        }
        break;
    case SYNTAXLL1:
        ui->CompileOutput->append("LL1 Syntax Analysis had been done!!\n");
        break;
    case SYNTAXRD:
        if(parserLL1())
        {
            outputParserTree(LLtreeroot,"parserLL1Tree.txt");

            ui->CompileOutput->append("Syntax Analysis LL result:\n==========\n");

            appendFileToTextEdit("parserLL1Tree.txt",*ui->CompileOutput);
            status = SYNTAX;
        }
        else
        {
            outputParserLL1Errors(false,"parserLL1Errors.txt");
            ui->ErrorMessage->append("LL1 Syntax Analysis runs wrong!!\n");
            appendFileToTextEdit("parserLL1Errors.txt", *ui->ErrorMessage);
            status = ERROR;
        }
        break;
    case SEMANTIC:
        ui->Console->append("Syntax Analysis had been done!!\n");
        break;
    case SYNTAX:
        ui->Console->append("Syntax Analysis has both been done!!\n");
        break;
    case ERROR:
        ui->Console->append("Errors happen in this SNL program!!\nLL1 analysis can not be done..\n");
        break;
    default:
        break;
    }
}

//语义分析
void MainWindow::on_actionSemantic_Analysis_triggered()
{
    CodeEditor * curEditor = dynamic_cast<CodeEditor *>(ui->editorTabWidget->currentWidget());
    curEditor->saveToFile();
    QString filePath = curEditor->getFilePath();
    if(status == SYNTAX || status == SYNTAXLL1)
    {
        if(analyze(getParserLL1TreeRoot()))
        {
            ui->CompileOutput->append("Semantic Analysis result:\n============\n");
            appendFileToTextEdit("Semout.txt",*ui->CompileOutput);
        }
        else
        {
            outputErrorlist(false,"semanticsError.txt");

            ui->ErrorMessage->append("Semantic Analysis runs wrong!!\n");
            appendFileToTextEdit("semanticsError.txt", *ui->ErrorMessage);
        }

        status = SEMANTIC;
    }
    else if(status == SYNTAXRD)
    {
        parserLL1();
        if(analyze(getParserLL1TreeRoot()))
        {
            ui->CompileOutput->append("Semantic Analysis result:\n============\n");
            appendFileToTextEdit("Semout.txt",*ui->CompileOutput);
        }
        else
        {
            outputErrorlist(false,"semanticsError.txt");

            ui->ErrorMessage->append("Semantic Analysis runs wrong!!\n");
            appendFileToTextEdit("semanticsError.txt", *ui->ErrorMessage);
        }

        status = SEMANTIC;
    }
    else if(status == SEMANTIC)
    {
        ui->Console->append("Semantic Analysis had been done!!");
    }
    else if(status == UNCOMPILED || status == LEXICAL)
    {
        on_actionLexical_Analysis_triggered();
        if(status == ERROR)
            return;
        on_actionLL_1_triggered();
        if(status == ERROR)
            return;
        on_actionSemantic_Analysis_triggered();
    }
    else
    {
        ui->Console->append("Errors happen in this SNL program!!\nSemantic analysis can not be done..\n");
    }
}
